using System.Collections.Generic;
using System.IO;
using FibMatrix.IO;
using FM_Mono;

namespace FibMatrix.Utils
{
    /// <summary>
    /// 随包的bundle会合并成一个或多个大文件(fragment)，此类负责把bundle在资源列表中的路径 映射到 对应大文件的偏移
    /// 支持不合并的情况，_fragmentPathList为空，_offsetTable仍会有数据
    /// </summary>
    [IgnoreGen]
    public class DefaultOffsetMapper:IBundleFileMapper
    {
        private string[] _fragmentPathList;

        private Dictionary<string, long> _offsetTable;

        private SearchPath _searchPath;
        
        public DefaultOffsetMapper(SearchPath searchPath, string[] fragmentsList, byte[] offsetTableBytes)
        {
            _searchPath = searchPath;
            _fragmentPathList = fragmentsList;
            if (fragmentsList == null && offsetTableBytes == null)
            {
                _offsetTable = new Dictionary<string, long>();
                return;
            }
            using (MemoryStream ms = new MemoryStream(offsetTableBytes))
            using (BinaryReader br = new BinaryReader(ms))
            {
                var count = br.ReadInt32();
                _offsetTable = new Dictionary<string, long>(count);
                for (int i = 0; i < count; ++i)
                {
                    var key = br.ReadString();
                    var val = br.ReadInt64();
                    _offsetTable.Add(key, val);
                }
            }
        }


        public SearchPath searchPath => _searchPath;

        /// <summary>
        /// 查找bundle在合并大bundle中的偏移
        /// </summary>
        /// <param name="relativePath"></param>
        /// <param name="mappingRelativePath"></param>
        /// <param name="offset">-1表示没找到</param>
        public void GetFileInfo(string relativePath, out string mappingRelativePath, out int offset)
        {
            mappingRelativePath = relativePath;
            offset = -1;    // 默认-1表示查找失败
            if (!_offsetTable.TryGetValue(relativePath, out var rawInfo))
            {
                return;
            }

            if (rawInfo != -1)
            {
                offset = (int) (rawInfo & 0xffffffff);
                int fragmentIndex = (int) (rawInfo >> 32);
                if (_fragmentPathList != null)
                    mappingRelativePath = _fragmentPathList[fragmentIndex];                
            }
        }
    }
}